package vip.zhenzicheng.test.juc.atomic;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * 通过版本号解决CAS的ABA问题
 *
 * @author zhenzicheng
 * @date 2022-09-06 11:01
 */
@Slf4j
public class ABACase {

  static AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<>(100, 1);

  public static void main(String[] args) {
    new Thread(() -> {
      int stamp = stampedReference.getStamp();
      log.info("{}\t 首次版本号: {}", Thread.currentThread().getName(), stamp);
      // 等待t4启动
      try {
        TimeUnit.MILLISECONDS.sleep(500);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      // ABA 过程
      stampedReference.compareAndSet(100, 101, stampedReference.getStamp(), stampedReference.getStamp() + 1);
      log.info("{}\t 2次版本号: {}", Thread.currentThread().getName(), stampedReference.getStamp());
      stampedReference.compareAndSet(101, 100, stampedReference.getStamp(), stampedReference.getStamp() + 1);
      log.info("{}\t 3次版本号: {}", Thread.currentThread().getName(), stampedReference.getStamp());
    }, "t3").start();

    new Thread(() -> {
      int stamp = stampedReference.getStamp();
      log.info("{}\t 首次版本号: {}", Thread.currentThread().getName(), stamp);
      // 等待t3 ABA
      try {
        TimeUnit.SECONDS.sleep(1);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      // 通过时间戳可以发现 ABA 问题
      boolean b = stampedReference.compareAndSet(100, 2022, stamp, stamp + 1);
      log.info("修改状态: {}, 当前版本号: {}", b, stampedReference.getStamp());
    }, "t4").start();
  }
}
